
package cz.czu.pef.DataModelling;

import java.util.*;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.persistence.*;

import org.hibernate.annotations.Index;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cz.czu.pef.DataModelling.utils.Lazy;

/**
 * This entity represents Company with its relations to addresses, employees, external workers and machineries.
 * 
 * @author rstribrn
 *
 */
@Entity
@Table(name="COMPANIES")
@Inheritance(strategy=InheritanceType.JOINED)
@NamedQueries({
	@NamedQuery(name="findCompanyByName", query="SELECT c FROM Company c WHERE c.name = :name"),
	@NamedQuery(name="findCompanyByIco", query="SELECT c FROM Company c WHERE c.ico = :ico")
})
@ManagedBean(name="company")
@ViewScoped
@Component
@Scope(value="prototype")
public class Company extends IdPersistenceObject
{
	private static final long serialVersionUID = -3846628860514746169L;

	/*
	 * Entity attributes
	 */
	@Column(name="COMPANY_NAME", nullable=false, length=200)
	@Index(name="IDX_COMPANY_NAME")
	private String name;

	@Column(name="COMPANY_ICO", nullable=false, length=32)
	@Index(name="IDX_COMPANY_ICO")
	private String ico;

	@Column(name="COMPANY_DIC", nullable=true, length=32)
	@Index(name="IDX_COMPANY_DIC")
	private String dic;

	@ManyToOne(fetch=FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
	private Address baseAddress;

	@ManyToMany(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
	@JoinTable(name="BRANCH_COMPANIES_ADDRESSES")
	private Set<Address> branchAddresses;

	/*
	 * Relations
	 */
	@ManyToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
	@JoinTable(name="COMPANIES_EMPLOYEES")
	private Set<Employee> employees;

	@ManyToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
	@JoinTable(name="COMPANIES_EXTERNAL_WORKERS")
	private Set<ExternalWorker> extWorkers;

	@OneToMany(fetch=FetchType.LAZY, targetEntity=Machinery.class, mappedBy="companyOwner") // no cascade!
	private Set<Machinery> machinery;

	protected Company()
	{
		super();
	}

	public Company(final String name, final String ico, final String dic)
	{
		setName(name);
		setIco(ico);
		setDic(dic);
	}

	
	public String getName()
	{
		return name;
	}

	
	public void setName(String name)
	{
		this.name = name;
	}

	
	public String getIco()
	{
		return ico;
	}

	
	public void setIco(String ico)
	{
		this.ico = ico;
	}

	public String getDic()
	{
		return dic;
	}

	public void setDic(String dic)
	{
		this.dic = dic;
	}
	
	public Address getBaseAddress()
	{
		return baseAddress;
	}

	
	public void setBaseAddress(Address baseAddress)
	{
		this.baseAddress = baseAddress;
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<Address> getBranchAddresses()
	{
		return branchAddresses;
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<Address> getBranchAddressesAsList()
	{
		return new ArrayList<Address>(getBranchAddresses());
	}

	public void addBranchAddress(Address address)
	{
		if (branchAddresses == null)
			branchAddresses = new HashSet<Address>();
		branchAddresses.add(address);
	}

	public void hireEmployee(Employee employee)
	{
		if (employees == null)
			employees = new HashSet<Employee>();
		employees.add(employee);
	}

	public void hireExternalWorker(ExternalWorker employee)
	{
		if (extWorkers == null)
			extWorkers = new HashSet<ExternalWorker>();
		extWorkers.add(employee);
	}
	
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<Employee> getEmployees()
	{
		return employees;
	}
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<Employee> getEmployeesAsList()
	{
		return new ArrayList<Employee>(getEmployees());
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<ExternalWorker> getExtWorkers()
	{
		return extWorkers;
	}
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<ExternalWorker> getExtWorkersAsList()
	{
		return new ArrayList<ExternalWorker>(getExtWorkers());
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<Machinery> getMachinery()
	{
		return machinery;
	}
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<Machinery> getMachineryAsList()
	{
		return new ArrayList<Machinery>(getMachinery());
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	@Override
	public String toString()
	{
		StringBuilder builder = new StringBuilder();
		builder.append("Company [name=");
		builder.append(getName());
		builder.append(", ico=");
		builder.append(getIco());
		builder.append(", baseAddress=");
		builder.append(getBaseAddress());
		builder.append(", branchAddresses=");
		builder.append(getBranchAddresses());
		builder.append(", employees=");
		builder.append(getEmployees());
		builder.append(", extWorkers=");
		builder.append(getExtWorkers());
		builder.append(", machinery=");
		builder.append(getMachinery());
		builder.append(", toString()=");
		builder.append(super.toString());
		builder.append("]");
		return builder.toString();
	}

	/**
	 * Can be deleted after no machinery is owned by this company.
	 */
	@Override
	public boolean canBeRemoved()
	{
		return getMachinery().size() == 0; 
	}

}